﻿using MiniFox.Cache.Configurations;
using MiniFox.Caching;
using MiniFox.Utility;
using StackExchange.Redis;

namespace MiniFox.Cache
{
    /// <summary>
    /// 
    /// </summary>
    public class RedisProvider : CacheProvider
    {
        private static readonly object locker;
        private static ConnectionMultiplexer connectionMultiplexer;

        static RedisProvider()
        {
            locker = new object();
        }
        /// <summary>
        /// 
        /// </summary>
        public RedisProvider() : this(3600)
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="defaultExpireSeconds"></param>
        public RedisProvider(int defaultExpireSeconds) : this(string.Empty, string.Empty, defaultExpireSeconds)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="keyPrefix"></param>
        /// <param name="keySuffix"></param>
        /// <param name="defaultExpireSeconds"></param>
        public RedisProvider(string keyPrefix, string keySuffix, int defaultExpireSeconds) : base(keyPrefix, keySuffix, defaultExpireSeconds)
        {
        }
        /// <summary>
        /// 
        /// </summary>
        protected static RedisConfiguration RedisConfig
        {
            get
            {
                return CacheService.CacheConfig.Redis;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        protected static ConnectionMultiplexer Connection
        {
            get
            {
                lock (locker)
                {
                    if (connectionMultiplexer == null)
                    {
                        var config = ConfigurationOptions.Parse(RedisConfig.FullHost);
                        
                        config.Password = RedisConfig.Password;
                        connectionMultiplexer = ConnectionMultiplexer.Connect(config);
                        connectionMultiplexer.ConnectionFailed += ConnectionMultiplexer_ConnectionFailed;
                    }
                }

                return connectionMultiplexer;
            }
        }

        private static void ConnectionMultiplexer_ConnectionFailed(object? sender, ConnectionFailedEventArgs e)
        {
        }
        /// <summary>
        /// 
        /// </summary>
        protected static IDatabase Database
        {
            get
            {
                return Connection.GetDatabase(RedisConfig.Database);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public override void RemoveAll()
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="timeSpan"></param>
        protected override void AddItem(string key, object value, TimeSpan timeSpan)
        {
            Database.StringSet(key, value.ToJsonString(), timeSpan);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected override bool ContainItem(string key)
        {
            return Database.KeyExists(key);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        protected override object GetItem(string key)
        {
            return Database.StringGet(key);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="val"></param>
        /// <returns></returns>
        protected override T Convert<T>(object val)
        {
            string json = val == null ? null : val.ToString();
            return json.ToJsonObject<T>();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <exception cref="NotImplementedException"></exception>
        protected override void RemoveItem(string key)
        {
            Database.KeyDelete(key);
        }
    }
}
